package com.sf.dlb.web.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sf.dlb.service.BaseUserDlbRecordService;
import com.sf.dlb.service.UserMessageService;
import com.sf.dlb.web.config.Global;
import com.sf.dlb.constant.CacheConstant;
import com.sf.dlb.constant.ResponseConstant;
import com.sf.dlb.jpa.model.*;
import com.sf.dlb.jpa.repository.UserInfoRepository;
import com.sf.dlb.jpa.repository.UserWalletRepository;
import com.sf.dlb.jpa.repository.UserWarningRepository;
import com.sf.dlb.jpa.repository.WalletLockRepository;
import com.sf.dlb.mapper.dao.WarningMapper;
import com.sf.dlb.utils.*;
import com.sf.dlb.vo.PageVO;
import com.sf.dlb.vo.ResultVO;
import com.sf.dlb.vo.WalletListVO;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 用户预警
 * Created by tanjing on 2019/4/17.
 */
@Service
public class UserWarningService {
    private Logger logger= LoggerFactory.getLogger(UserWarningService.class);
    @Autowired
    private WarningMapper warningMapper;
    @Autowired
    private UserWarningRepository userWarningRepository;
    @Autowired
    private UserInfoRepository userInfoRepository;
    @Autowired
    private UserWalletRepository userWalletRepository;
    @Autowired
    private BaseUserDlbRecordService userDlbRecordService;
    @Autowired
    private WalletLockRepository walletLockRepository;
    @Autowired
    private UserMessageService userMessage;
    @Autowired
    private UserInfoService userInfoService;
    @Resource
    private Global global;
    @Autowired
    public RedisUtil redisUtil;

    /**
     * 预警
     */
    public void warning(String date){
        logger.info("warning date={}",date);
        String yesterDay=DateUtils.addTimeByDay(new Date(),-1);
        if(StringUtils.isNotBlank(date)){
            yesterDay=date;
        }
        int maxReadTime=global.user_warning_max_read_long;
        int maxReadNumber=global.user_warning_max_read_number;
        int day=global.user_warning_max_read_number;
        // 预警因子
        List<UserWarningInfo> warningMap1=warningReadTime(yesterDay,maxReadTime);
        List<UserWarningInfo> warningMap2=warningReadNumber(yesterDay,maxReadNumber);
        List<UserWarningInfo> warningMap3=warningRegisteredNoRead(day);
        //保存到预警表
        ArrayList<UserWarningInfo> userWarningInfos=new ArrayList<>();
        userWarningInfos.addAll(warningMap1);
        userWarningInfos.addAll(warningMap2);
        userWarningInfos.addAll(warningMap3);

        String currentDate=DateUtils.getDate("yyyy-MM-dd");
        for (UserWarningInfo userWarningInfo:userWarningInfos) {
            String userId=userWarningInfo.getUserId();
            //找出重复记录
            UserWarningInfo userWarningInfo1=warningMapper.queryUserIdAndDate(userId,currentDate);
            if(null==userWarningInfo1){
                userWarningRepository.save(userWarningInfo);
            }else{
                String warningWhy=userWarningInfo.getWarningWhy();
                userWarningInfo1.setWarningWhy(userWarningInfo1.getWarningWhy()+"&"+warningWhy);
                userWarningInfo1.setUpdateDate(new Date());
                userWarningRepository.save(userWarningInfo1);
            }
        }
        logger.info("warning userWarningInfos.size={}",userWarningInfos.size());
    }
    /**
     * 预警因子1-凡是某天累计阅读时间超过3个小时
     * -有效阅读
     */
    public List<UserWarningInfo> warningReadTime(String yesterDay,int maxReadLong){
        logger.info("warningReadTime yesterDay={},maxReadLong={}",yesterDay,maxReadLong);
        List<Map> warningMap1=warningMapper.warningReadTime(yesterDay,"1",maxReadLong);
        ArrayList<UserWarningInfo> userWarningInfos1=new ArrayList<>();
        for (Map tempMap:warningMap1) {
            String userId = (String) tempMap.get("user_id");
            BigDecimal readLongB = (BigDecimal) tempMap.get("read_long");
            String readLongStr=DateUtils.timeFormatHourAndMin(readLongB.intValue());
            UserWarningInfo userWarningInfo=new UserWarningInfo();
            userWarningInfo.setUserId(userId);
            userWarningInfo.setWarningWhy("阅读时间"+readLongStr);
            userWarningInfo.setDealtState("1");//默认未处理
            userWarningInfo.setCreateDate(new Date());
            userWarningInfo.setUpdateDate(new Date());
            userWarningInfos1.add(userWarningInfo);
        }
        logger.info("warningReadTime warningMap1.size={}",warningMap1.size());
        return userWarningInfos1;
    }
    /**
     * 预警因子2-凡是某天累计阅读数量超过300篇；
     */
    public List<UserWarningInfo> warningReadNumber(String yesterDay,int maxReadNumber){
        logger.info("warningReadNumber yesterDay={},maxReadNumber={}",yesterDay,maxReadNumber);
        List<Map> warningMap1=warningMapper.warningReadNumber(yesterDay,maxReadNumber);
        ArrayList<UserWarningInfo> userWarningInfos1=new ArrayList<>();
        for (Map tempMap:warningMap1) {
            String userId = (String) tempMap.get("user_id");
            Long readNumber = (Long) tempMap.get("read_number");
            UserWarningInfo userWarningInfo=new UserWarningInfo();
            userWarningInfo.setUserId(userId);
            userWarningInfo.setWarningWhy("阅读数量"+readNumber.longValue()+"篇");
            userWarningInfo.setDealtState("1");//默认未处理
            userWarningInfo.setCreateDate(new Date());
            userWarningInfo.setUpdateDate(new Date());
            userWarningInfos1.add(userWarningInfo);
        }
        logger.info("warningReadNumber warningMap1.size={}",warningMap1.size());
        return userWarningInfos1;
    }
    /**
     * 预警因子3-注册后30天内无阅读量的；
     */
    public List<UserWarningInfo> warningRegisteredNoRead(int day){
        logger.info("warningRegisteredNoRead day={}",day);
        List<Map> warningMap1=warningMapper.warningRegisteredNoRead(day);
        ArrayList<UserWarningInfo> userWarningInfos1=new ArrayList<>();
        //找出被冻结或禁止登陆的用户
        List<String> forBidUserList=userInfoService.userForbidList();
        for (Map tempMap:warningMap1) {
            String userId = (String) tempMap.get("user_id");
            Date createDate = (Date) tempMap.get("create_date");
            //冻结的用户不需要再预警了
            boolean repeatFlag=true;
            for (String tempUserId:forBidUserList) {
                if(StringUtils.equals(tempUserId,userId)){
                    repeatFlag=false;
                    break;
                }
            }
            if(!repeatFlag){
                continue;
            }
            UserWarningInfo userWarningInfo=new UserWarningInfo();
            userWarningInfo.setUserId(userId);
            userWarningInfo.setWarningWhy("注册时间"+DateUtils.formatDate(createDate,"yyyy-MM-dd"));
            userWarningInfo.setDealtState("1");//默认未处理
            userWarningInfo.setCreateDate(new Date());
            userWarningInfo.setUpdateDate(new Date());
            userWarningInfos1.add(userWarningInfo);
        }
        logger.info("warningRegisteredNoRead warningMap1.size={}",warningMap1.size());
        return userWarningInfos1;
    }
    /**
     * 预警列表
     */
    public ResultVO warningList(int page,int size){
        logger.info("warningList start page={},size={}",page,size);
        //分页查询
        PageHelper.startPage(page,size);
        List<Map> warnginAll=warningMapper.findByWarningAll();
        PageInfo<Map> pageInfo= new PageInfo<>(warnginAll);
//        封装VO
        List<WalletListVO> walletListVOS=new ArrayList<>();
        for (Map map:warnginAll) {
            String userId= (String) map.get("user_id");
            String warningWay=(String) map.get("warning_why");
            Long warningCount=(Long) map.get("warning_count");
            Long noHandlerDay=(Long) map.get("no_handler_day");
            String createDate= (String) map.get("create_date");
            WalletListVO walletListVO=new WalletListVO();
            walletListVO.setUserId(userId);
            walletListVO.setWarningWhy(warningWay);
            walletListVO.setWarningCount(warningCount+"");
            walletListVO.setNoHandlerDay(noHandlerDay+"");
            walletListVO.setCreateDate(DateUtils.parseDate(createDate).getTime());
            walletListVOS.add(walletListVO);
        }
        PageVO pageVO=new PageVO();
        pageVO.setDataList(walletListVOS);
        pageVO.setPageSize(size);
        pageVO.setCurrentPages(page);
        pageVO.setFirstPage((!pageInfo.isHasPreviousPage()));
        pageVO.setLastPage((!pageInfo.isHasNextPage()));
        pageVO.setTotalElements(pageInfo.getTotal());
        pageVO.setTotalPages(pageInfo.getPages());
        return ResultVOUtil.success(pageVO);
    }
    /**
     * 预警列表
     */
    public ResultVO warningListDetails(String userId){
        logger.info("warningListDetails start userId={}",userId);
        List<UserWarningInfo> userWarningInfos=userWarningRepository.findByUserIdAndDelFlagOrderByCreateDateDesc(userId,"0");
//        封装VO
        List<WalletListVO> walletListVOS=new ArrayList<>();
        for (UserWarningInfo userWarningInfo:userWarningInfos) {
            WalletListVO walletListVO=new WalletListVO();
            BeanUtils.copyProperties(userWarningInfo,walletListVO);
            walletListVO.setDealtStateValue(StateToValueUtils.switchDealtStateValue(userWarningInfo.getDealtState()));
            walletListVO.setCreateDate(userWarningInfo.getCreateDate().getTime());
            walletListVO.setHandlerDate(userWarningInfo.getUpdateDate().getTime());
            walletListVOS.add(walletListVO);
        }
        return ResultVOUtil.success(walletListVOS);
    }
    /**
     * 批量预警处理
     */
    @Transactional
    public ResultVO warningHandler(List<String> userIds, String dealtType,int dlbNumber){
        logger.info("warningHandler start userIds={},dealtType={},dlbNumber={}",userIds.size(),dealtType,dlbNumber);
        int handlerSuccessFulCount=0;
        int handlerFailureCount=0;
        for (String userId:userIds) {
            ResultVO resultVO=warningHandler(userId,dealtType,dlbNumber);
            if(null==resultVO||resultVO.getCode()!=200){
                handlerFailureCount++;
            }else{
                handlerSuccessFulCount++;
            }
        }
        logger.info("warningHandler handlerSuccessFulCount={},handlerFailureCount={}",handlerSuccessFulCount,handlerFailureCount);
        return ResultVOUtil.success();
    }
    /**
     * 预警处理
     */
    @Transactional
    public ResultVO warningHandler(String userId, String dealtType,int dlbNumber){
        logger.info("warningHandler start userId={},dealtType={},dlbNumber={}",userId,dealtType,dlbNumber);
        List<UserWarningInfo> userWarningInfos=userWarningRepository.findByUserIdAndDealtStateAndDelFlagOrderByCreateDateDesc(userId,"1","0");
        if(CollectionUtils.isEmpty(userWarningInfos)){
            return ResultVOUtil.error(ResponseConstant.ERROR,"预警数据不存在");
        }
        UserWarningInfo userWarningInfo=userWarningInfos.get(0);
        //预警预警被处理了
        if(!userWarningInfo.getDealtState().equals("1")){
            return ResultVOUtil.error(ResponseConstant.ERROR,"预警已被处理了");
        }
        //处理之后的逻辑
        String dealtValue;
        ResultVO resultVO=null;
        //处理类型(1-禁止3天登陆，2-冻结账号，3-回收奖励，4-忽略)
        switch (dealtType){
            case "1":
                dealtValue="禁止3天登陆";
                resultVO=warningHandlerCase1(userId);
                break;
            case "2":
                dealtValue="冻结账号";
                resultVO=warningHandlerCase2(userId);
                break;
            case "3":
                dealtValue="回收奖励"+dlbNumber;//回收奖励的数量
                resultVO=warningHandlerCase3(userId,dlbNumber,userWarningInfo.getId());
                break;
            case "4":
                dealtValue="忽略";
                resultVO=ResultVOUtil.success();
                break;
            default:
                dealtValue="";
                break;
        }
        if(null==resultVO||resultVO.getCode()!=200){
            logger.info("warningHandler null==resultVO&&resultVO.getCode()!=200");
            return resultVO;
        }
        //更新预警状态
        userWarningInfo.setDealtState("0");//已处理
        userWarningInfo.setDealtType(dealtType);
        userWarningInfo.setDealtDesc(dealtValue);
        userWarningInfo.setUpdateDate(new Date());
        userWarningRepository.save(userWarningInfo);
        logger.info("warningHandler userWarningInfo={}",GsonUtils.getInstance().toJson(userWarningInfo));
        //有积累的未处理预警，一并处理了；-》已过期；
        ArrayList<UserWarningInfo> userWarningInfoSave=new ArrayList<>();
        int i=0;
        for (UserWarningInfo userWarningInfo1:userWarningInfos) {
            if(i!=0){
                userWarningInfo1.setDealtState("2");//已过期
                userWarningInfo1.setUpdateDate(new Date());
                userWarningInfoSave.add(userWarningInfo1);
            }
            i++;
        }
        logger.info("warningHandler userWarningInfoSave={}",GsonUtils.getInstance().toJson(userWarningInfoSave));
        userWarningRepository.save(userWarningInfoSave);
        return ResultVOUtil.success();
    }
    /**
     *  1-禁止3天登陆
     */
    @Transactional
    public ResultVO warningHandlerCase1(String userId){
        logger.info("warningHandlerCase1 userId={}",userId);
        String key=CacheConstant.USER_CACHE+CacheConstant.BAN_USER_3DAY_LOGIN;
        redisUtil.set(key+userId,"1",60*60*24*3);
        redisUtil.sSet(key,userId);//同时保存被禁止用到到集合
        //推送消息
        String currentStr=DateUtils.formatDate(new Date(),"yyyy年MM月dd日");
        String message=currentStr+"系统检测到您的账号存在异常，已禁止3天内访问";
        userMessage.saveUserMessage(userId,"禁止3天登陆","1",message);
        return ResultVOUtil.success();
    }
    /**
     *  2-冻结账号
     */
    @Transactional
    public ResultVO warningHandlerCase2(String userId){
        logger.info("warningHandlerCase2 userId={}",userId);
        UserInfo userInfo=userInfoRepository.findByUserIdAndDelFlag(userId,"0");
        userInfo.setLoginFlag("1");
        userInfo.setUpdateDate(new Date());
        userInfoRepository.save(userInfo);
        //推送消息
        String currentStr=DateUtils.formatDate(new Date(),"yyyy年MM月dd日");
        String message=currentStr+"系统检测到您的账号存在异常，已冻结您的账号。";
        userMessage.saveUserMessage(userId,"冻结账号","1",message);
        return ResultVOUtil.success();
    }
    /**
     *  3-回收奖励
     *  @param userId
     *  @param dlbNumber
     *  @param id  预警ID
     */
    @Transactional
    public ResultVO warningHandlerCase3(String userId,int dlbNumber,Long id){
        logger.info("warningHandlerCase3 userId={},dlbNumber={}",userId,dlbNumber);
        UserWalletInfo userWalletInfo= userWalletRepository.findByUserIdAndDelFlag(userId,"0");
        if(null==userWalletInfo){
            logger.info("updateUserWalletSub userWalletInfo is null");
            return ResultVOUtil.error(ResponseConstant.ERROR,"钱包暂无数据");
        }
//      判断dlb是否足够,计算可回收值
//        充值>=支出    可回收<=赚取的(总收入dlb-充值dlb)
//        充值<=支出  可回收<=总收入-总指出
        Double addDlb=warningMapper.queryUserDlbRecordAndDlbType(userId,"1");//总收入dlb
        Double subDlb=warningMapper.queryUserDlbRecordAndDlbType(userId,"2");//总支出dlb
        Double topUpDlb=warningMapper.queryUserDlbRecordAndSource(userId,"5");//充值dlb
        addDlb=(null==addDlb?0.0:addDlb);
        subDlb=(null==subDlb?0.0:subDlb);
        topUpDlb=(null==topUpDlb?0.0:topUpDlb);
        double earnDdlb=Arith.sub(addDlb,topUpDlb);//赚取的(总收入dlb-充值dlb)
        double recycled=0.0;//可回收的
        if(topUpDlb>=subDlb){
            recycled =earnDdlb;
        }else {
            recycled =Arith.sub(addDlb,subDlb);
        }
        logger.info("warningHandlerCase3 addDlb={},subDlb={},recycled={}",addDlb,subDlb,recycled);
        if(dlbNumber>recycled){
            logger.info("warningHandlerCase3 dlbNumber>balansDlb");
            return ResultVOUtil.error(ResponseConstant.ERROR,"用户dlb余额不足");
        }
        //更新钱包
        // 可用的dlb是否足够-》(锁定的+可用的)dlb是否足够-》(解锁中的+锁定的+可用的)dlb是否足够
        Double availableDlb=userWalletInfo.getAvailableDlb();
        Double unlockDlb=userWalletInfo.getUnlockDlb();
        Double lockDlb=userWalletInfo.getLockDlb();
        availableDlb=(null==availableDlb?0.0:availableDlb);
        unlockDlb=(null==unlockDlb?0.0:unlockDlb);
        lockDlb=(null==lockDlb?0.0:lockDlb);
        Double availableDlbNew=0.0;
        Double unlockDlbNew=0.0;
        Double lockDlbNew=0.0;
        if(dlbNumber<=availableDlb){
            availableDlbNew=Arith.sub(availableDlb,dlbNumber);
            unlockDlbNew=unlockDlb;
        }else if(dlbNumber<=(Arith.add(lockDlb,availableDlb))){
            lockDlbNew=Arith.sub(lockDlb,Arith.sub(dlbNumber,availableDlb));
            unlockDlbNew=unlockDlb;
        }else if(dlbNumber<=(Arith.add(unlockDlb,Arith.add(lockDlb,availableDlb)))){
            int tempRemainDlb=Arith.sub(dlbNumber,Arith.add(lockDlb,availableDlb));
            unlockDlbNew=Arith.sub(unlockDlb,tempRemainDlb);
            //处理解锁记录
            List<WalletLockInfo> walletLockInfos=walletLockRepository.findByUserIdAndLockStateAndDelFlagOrderByCreateDateDesc(userId,"3","0");
            for (WalletLockInfo walletLockInfo:walletLockInfos) {
                double tempLockCount=walletLockInfo.getLockCount();
                int tempDifference=Arith.sub(tempRemainDlb,tempLockCount);
                tempRemainDlb=tempDifference;
                if(tempDifference>0){
                    walletLockInfo.setLockCount((double)tempDifference);
                    walletLockInfo.setUpdateDate(new Date());
                    walletLockRepository.save(walletLockInfo);
                    continue;
                }else{
                    walletLockInfo.setDelFlag("1");
                    walletLockInfo.setUpdateDate(new Date());
                    walletLockRepository.save(walletLockInfo);
                    continue;
                }
            }
        }else{
            logger.info("warningHandlerCase3 钱包余额不足");
            return ResultVOUtil.error(ResponseConstant.ERROR,"钱包余额不足");
        }
        userWalletInfo.setAvailableDlb(availableDlbNew);
        userWalletInfo.setUnlockDlb(unlockDlbNew);
        userWalletInfo.setLockDlb(lockDlbNew);
        userWalletInfo.setUpdateDate(new Date());
        userWalletRepository.save(userWalletInfo);
        logger.info("warningHandlerCase3 availableDlbNew={},unlockDlbNew={},lockDlbNew={} ",availableDlbNew,unlockDlbNew,lockDlbNew);
        //更新流水表
        userDlbRecordService.generateDlbRecord(userId,ResponseConstant.source_type_recycling, ResponseConstant.source_type_recycling_value+":预警记录id:"+id,(double)dlbNumber,ResponseConstant.type_sub);
        //推送消息
        String currentStr=DateUtils.formatDate(new Date(),"yyyy年MM月dd日");
        String message=currentStr+"系统检测到您是机器人，已回收您部分奖励，回收奖励"+dlbNumber+"dlb";
        userMessage.saveUserMessage(userId,"回收奖励","1",message);
        return ResultVOUtil.success();
    }
}
